package com.cw.jeeyt.core.impl.facadeExcel;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cw.jeeyt.api.dto.facadeExcel.ClassFileInfo;

/**
 * @description: 类加载
 * @author: chenw
 * @create: 2018-12-16 12:41
 */

/**
 * 自定义的类加载器
 *
 * @author linxz
 */
@Component
public class MyClassLoader extends ClassLoader {
    private static Logger logger = LoggerFactory.getLogger(MyClassLoader.class);
    private static Map<String,Class> classMap = new HashMap<>();
    @Autowired
    private FileSearchCore fileSearchCore;
    private static MyClassLoader loader = new MyClassLoader();

    /**
     * @param name class 类的文件名
     * @param pack 类所在的包名 eg:com.szelink.test.  后面需要带个"."<br>
     * @param file 类文件的路径，设定目录时，需要在最后带上"/"
     * 自定义路径获取Class对象
     */
    public static Class<?> findClassByNameAndLocation(String name, String pack, File file){
        //将class文件的数据读入到byte数组中
        byte[] datas = loader.loadClassData(file);
        pack = loader.convert(pack);
        //通过byte数组加载Class对象
        return loader.defineClass(pack + name, datas, 0, datas.length);
    }

    /**
     * @param fileType .class
     * @param filePrefix Enum
     * @param classPatterns
     * @param basePath 包所在的路径
     * @return
     */
    public void findClassesByLocation(Map classFileInfos,String baseClassPath , String basePath,String fileType,String filePrefix,String classPatterns) {
        fileSearchCore.emptyFileList();
        String [] classPatternList = classPatterns.split(",");
        for(String classPattern : classPatternList){
            //列出所有的.class文件
            List<ClassFileInfo> fileList = fileSearchCore.getFileList(baseClassPath,basePath,fileType,filePrefix,classPattern);
            for (ClassFileInfo classFileInfo : fileList) {
                String classCode = classFileInfo.getClassCode();
                logger.info("加载类：{}",classCode);
                String packageName = classFileInfo.getPackagePath();
                try{
                    //Class c = Class.forName(packageName + classCode);
                    Class c = null;
                    try{
                        c = classMap.get(packageName + classCode);
                    }catch (Exception e){
                        logger.debug("redis缓存获取类【{}】失败",packageName+classCode);
                    }
                    if(c == null){
                        c = findClassByNameAndLocation(classCode, packageName, classFileInfo.getClassFile());
                        classMap.put(packageName + classCode,c);
                    }
                    classFileInfos.put(packageName + classCode, c);
                }catch (Exception e){
                    logger.error("找不到类{}",classCode);
                }catch (NoClassDefFoundError ee){
                    ee.printStackTrace();
                    logger.error("找不到类{}",classCode);
                }
            }
        }
    }

    /**
     * 将.class文件读入到byte[]数组中
     *
     * @param classFile 要读取的文件目录
     * @return 读取到的byte[]数组
     */
    protected byte[] loadClassData(File classFile) {
        FileInputStream fis = null;
        byte[] datas = null;
        try {
            fis = new FileInputStream(classFile);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int b;
            while ((b = fis.read()) != -1) {
                bos.write(b);
            }
            datas = bos.toByteArray();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return datas;

    }

    /**
     * 转换包名
     *
     * @param pack 要转换的包名
     * @return
     */
    private String convert(String pack) {
        String result = "";
        //将所有的/转成.
        result = pack.replace('/', '.');
        //将所有的\转成.
        result = result.replace('\"', '.');
        result = result.replace('\\', '.');
        //判断最后一位是否为.，若不是，加上一个.
        if (!(result.substring(result.length() - 1)).equals(".")) {
            result += ".";
        }
        return result;
    }

    public static void main(String[] args) {

        //findClassesByLocation("D:\\yunrong\\classes",".class","Enum","com\\cw");
    }
}
